package system

import (
	"context"
	"gf_blog_admin/internal/model"
	"gf_blog_admin/internal/service"
	"gf_blog_admin/utility/storager"
	"gf_blog_admin/utility/utils"
	"github.com/gogf/gf/v2/errors/gerror"
	"github.com/gogf/gf/v2/frame/g"
	"github.com/gogf/gf/v2/os/gtime"
)

type sSysUpload struct{}

func init() {
	service.RegisterSysUpload(NewSysUpload())
}

func NewSysUpload() *sSysUpload {
	return &sSysUpload{}
}

// UploadFile 上传文件
func (s *sSysUpload) UploadFile(ctx context.Context, in *model.UploadFileInput) (out *model.UploadFileItem, err error) {
	if in.File == nil {
		return nil, gerror.New("没有找到上传的文件")
	}

	file, err := storager.DoUpload(ctx, in.File)
	if err != nil {
		return nil, err
	}

	out = &model.UploadFileItem{
		FileName: file.FileName,
		Location: storager.LastUrl(ctx, file.FilePath, file.FileStorage),
		Key:      file.FilePath,
		ETag:     file.FileMd5,
	}
	return
}

func (s *sSysUpload) InitMultipart(ctx context.Context) (out *model.UploadInitMultipart, err error) {
	mp, err := storager.InitMultipart(ctx)
	if err != nil {
		return nil, err
	}
	out = &model.UploadInitMultipart{
		UploadId: mp.UploadId,
		ExpireIn: mp.ExpireAt.Unix(),
	}
	return
}

// UploadPart 上传分片
func (s *sSysUpload) UploadPart(ctx context.Context, in *model.UploadPartInput) (out *model.UploadPartItem, err error) {
	result, err := storager.UploadPart(ctx, &storager.UploadPartParams{
		UploadId:   in.UploadId,
		PartNumber: in.PartNumber,
		File:       in.File,
	})
	if err != nil {
		return nil, err
	}

	out = &model.UploadPartItem{
		PartNumber: result.PartNumber,
		ETag:       result.ETag,
	}
	return
}

func (s *sSysUpload) CompleteMultipart(ctx context.Context, in *model.UploadMultipartInput) (out *model.UploadFileItem, err error) {
	var parts = make([]*storager.MultipartItem, len(in.Parts))
	for i, part := range in.Parts {
		parts[i] = &storager.MultipartItem{
			PartNumber: part.PartNumber,
			ETag:       part.ETag,
		}
	}
	file, err := storager.CompleteMultipart(ctx, &storager.CheckMultipartParams{
		UploadId: in.UploadId,
		Parts:    parts,
	})
	if err != nil {
		return nil, err
	}
	out = &model.UploadFileItem{
		FileName: file.FileName,
		Location: storager.LastUrl(ctx, file.FilePath, file.FileStorage),
		Key:      file.FilePath,
		ETag:     file.FileMd5,
	}
	return
}

func (s *sSysUpload) AbortMultipart(ctx context.Context, uploadId string) error {
	return storager.AbortMultipart(ctx, uploadId)
}

func (s *sSysUpload) ListParts(ctx context.Context, in *model.UploadListPartInput) (out *model.UploadListPartOutput, err error) {
	res, err := storager.ListParts(ctx, in.UploadId)
	if err != nil {
		return nil, err
	}

	var parts = make([]*model.UploadListPartItem, 0)
	for _, part := range res.Parts {
		num := len(parts)
		if in.MaxParts > 0 && num >= in.MaxParts {
			continue
		}
		parts = append(parts, &model.UploadListPartItem{
			PartNumber: part.PartNumber,
			ETag:       part.ETag,
			Size:       part.Size,
			PutTime:    gtime.New(part.LastModified),
		})
	}
	out = &model.UploadListPartOutput{
		UploadId:             in.UploadId,
		ExpireAt:             gtime.New(res.ExpireAt),
		PartNumberMarker:     res.PartNumberMarker,
		NextPartNumberMarker: res.NextPartNumberMarker,
		ShardCount:           res.ShardCount,
		Parts:                parts,
	}
	return
}

func (s *sSysUpload) UploadThirdToken(ctx context.Context, drive string) (string, error) {
	backUrl := utils.GetAddr(ctx) + "/api/file/upload/callback"
	if drive == storager.UploadDriveQiNiu {
		return storager.GetQiNiuDrive().GetToken(ctx, backUrl)
	}
	return "", gerror.New("当前驱动暂不支持")
}

func (s *sSysUpload) UploadCallback(ctx context.Context, in *model.UploadCallbackInput) error {
	if ok, err := storager.GetQiNiuDrive().VerifyCallback(ctx); err != nil {
		return err
	} else if ok {
		g.Log().Info(ctx, "七牛上传回调参数：", in)
	}
	return gerror.New("internal error")
}
